第6章 テスト駆動開発
変更に対して安全なアーキテクチャの設計を、確かに動くものとして作っていく方法(扉)
単体テスト(6-2)
最小単位のテスト技法
工程ごとに小さなスコープで部品品質の保証を積み上げるのが、単体テストの考え方です。(Kindle 版 p.204)
品質保証した下位の部品を上位で使う
テストコードは、実際にそのモジュールを使うプログラミング言語と同じ言語で書きます。(Kindle 版 p.204)
5章でも出た飽和関数の例
xUnitでテストコードを書き始める(6-3)
最初に書いた例
Mathクラスのインスタンスのminメソッド・maxメソッドを呼ぶ1つのテスト
xUnitの考え方
TestCaseクラスの継承
アサーションメソッドが追加される
引数の順序
Pythonはfirstとsecondなので、考え方がやや違う!
複数のアサーション
より適したメソッドを使うことで、失敗状況を表すメッセージが適切なものになります。(Kindle 版 p.213)
(pytestだと弱まることになる?)
実装から何を検証しようとしているかの意図がわかる
minとmaxの動作を一度にテストは伸びしろ
それぞれ徹底的にテスト
例:負の数、整数の最大や最小を扱えるか
minとmaxで徹底的にテスト済みなので、saturateは負の数などを考えなくてよい
上位のモジュールでテストシナリオのパターンが際限なく増えずに済む
際限なく増えた状態=結合機能テスト
以前と同じテストをすべて再実行することを回帰テスト(リグレッションテスト)と呼びます。(Kindle 版 p.219)
単体テストのコードの山
常に回帰テストし続けられる!
スタブとモック(6-4)
オブジェクト指向らしいxUnitの使い方
前提仮説(=使い方)
振る舞いに代えて
テストされてバグがない振る舞いに依存するつらみが語られる。テストしているかによらず、期待どおりに動いたとしてという前提仮説を採用する
スタブ:テスト用の疑似オブジェクト
Mathをスタブで用意して、MathUtilに渡す
maxが呼ばれたら2を返すというように設定しておく
MathUtilに着目しているときは、Mathの内部バグの可能性を完全に忘れて、MathUtilTestを自己完結させられます。(Kindle 版 p.223)
テストは実際に動くとまずいものはスタブにする
ちょうぜつ本ではスタブ用途でもcreateMockしている
モック
単体テストの文脈でいうモックとは、使われ方を検証するための疑似オブジェクトのことです。(Kindle 版 p.224)
例:Pythonでは、assert_called_once_withなど!
テストコードでアサーションできる
仕様通りに使っている
一般的には、単一パッケージ内のクラス関係は、直接依存で単体テストを書き、異なるパッケージのクラスを使う場合だけモック化するのがオススメです。(Kindle 版 p.226)
REPにより、パッケージ内なら複数のテストが落ちても全部直せる
テストが落ちるからと複数のパッケージを同時に直したくはない
単体テストしにくい設計はオブジェクト指向というパラダイムに乗り切れていない
IMO:無理やりやってしまうライブラリもあるように見える(例:モックサーバ)
関連しそう
テストファーストで書く(BDD)6-5
テスト駆動開発の基礎についての節
実装よりもテストを先に書く=テストファースト
テストコードと実装の振る舞いが同じ歩調で育ちます (Kindle版 p.240)
動く仕様ドキュメント(テストコード)
漏れがなく、対応する実装
IMO:実装だけあってテストがない -> 将来負債となりがち
手順
実行できるけれど失敗するテスト(Red)
テストをパスする最小限の実装(Green)
テストを追加
成功したらさらにテスト追加
失敗したらパスする最小限の実装
サイクルを回していく(が、サイクルも最小限に)
FizzBuzzを例に
1
固定値で返す
2
引数の整数を文字列にして返す
3
3のときの分岐を追加
IMO:elseは要らなくないか(早期リターンでいいのでは)
4
通る
5
5のときの分岐を追加
6
3の倍数のときの分岐に変更
10
7以降は通ると分かるので10を追加
5の倍数のときの分岐に変更
15
3の倍数でかつ5の倍数と分岐を追加して通る
リファクタリング(テストファーストのサイクルとは別で扱っている)
30
通る
ここまでやってコミットとのこと
IMO:TDDでは、一般化するには2例いることが見て取れる
DHHの「TDD is dead」
最短実装で動くフレームワークに対してさえも、過剰に細粒度なTDDを適用しては、なかなかアプリケーションを作らない開発者を見て、“TDD is dead”と表現 (Kindle版 p.243)
設計としてのTDD
5章のFizzBuzzの実装を生み出した秘密(設計技法を指南する節)
仮説から抽象を作る
replace
モックを使ってTDD
抽象を実装した具象の動きをモックで表現
本物のオブジェクトを組み合わせる
Fizz3となってうまくいかない
慌てて直そうという例は、単一責任選択の原則(ミノ駆動本 6章 条件分岐)やDRY原則に違反する例になっている モックのおかげでかなり抽象度が高いレベルの単体テストができ、それが最後あと一歩のところまで通じるまでの指針を示したことに、大きな価値があります。(Kindle版 p.262)
(IMO:アウト・サイド・インのTDDではなかった)
モックを使って動かしたことで気づけた。頭の中で考えていたら気づけない
ここで書いたテストは「捨て案」
抽象のアップデート
replaceの代わりに、applyとmatch
テストしたいことと無関係な変数には、明らかなダミー値を入れておく
プロパティを必要としない、純粋関数のようなオブジェクトも十分にありえます。(Kindle版 p.275)
データとメソッドを両方持たなければならないわけではない。メソッドのみもありうる
シンプルさこそが拡張性